#include "gtest/gtest.h"

#include "stream/impl/rocksdb/Rocksdb.h"
#include "stream/impl/rocksdb/Table.h"

using Rocksdb=stream::impl::rocksdb::Rocksdb;

class RocksdbTest : public testing::Test {
public:
	const std::string _dirname = "test-rocksdb.db";
	const std::string _defTabName = "default";
	const std::string newTabName = "meta";
	const std::string key = "hello";
};

TEST_F(RocksdbTest, testCreateIfMissing){
	Rocksdb db(_dirname);

    db.createIfMissing();
    ASSERT_TRUE(db.isOpened());

	auto && p = db.isTableExist(_defTabName);
	ASSERT_TRUE(p.first);

	ASSERT_TRUE(db.tables().size() >= 1);

    db.close();
    ASSERT_FALSE(db.isOpened());
}
TEST_F(RocksdbTest, testOpenExist){
    Rocksdb db(_dirname);

    db.openExist();
    ASSERT_TRUE(db.isOpened());

	auto p = db.isTableExist(_defTabName);
	ASSERT_TRUE(p.first);

	ASSERT_TRUE(db.tables().size() >= 1);

    db.close();
    ASSERT_FALSE(db.isOpened());
}

TEST_F(RocksdbTest, testEasy){
    Rocksdb db(_dirname);
    db.createIfMissing();// createIfMissing && open all column families

	auto table = db.getTable(_defTabName);
	ASSERT_TRUE(table != nullptr);

	const std::string key1 ="hello_1";
	ASSERT_TRUE(table->put(key1, "world1").ok());

	std::string v;
	ASSERT_TRUE(table->get(key1, v).ok());
	ASSERT_EQ(v, "world1");

	ASSERT_TRUE(table->del(key1).ok());

    db.close();
    ASSERT_FALSE(db.isOpened());
}
TEST_F(RocksdbTest, testCreateDropTable){
    Rocksdb db(_dirname);
    db.createIfMissing();// createIfMissing && open all column families

	auto && p = db.isTableExist(newTabName);
	if(false == p.first){
		auto table = db.createTable(newTabName);	
		ASSERT_TRUE(table != nullptr);

		const std::string key1 ="hello_1";
		ASSERT_TRUE(table->put(key1, "world1").ok());

		std::string v;
		ASSERT_TRUE(table->get(key1, v).ok());
		ASSERT_EQ(v, "world1");

		ASSERT_TRUE(table->del(key1).ok());

		ASSERT_TRUE(db.dropTable(newTabName));
	}
	
    db.close();
    ASSERT_FALSE(db.isOpened());
}

TEST_F(RocksdbTest, testGetPutDeleteInNewTable){
    Rocksdb db(_dirname);

    db.createIfMissing();
    ASSERT_TRUE(db.isOpened());

	auto && p = db.isTableExist(newTabName);
	if(!p.first){
		ASSERT_TRUE(db.createTable(newTabName) != nullptr);
	}
	ASSERT_TRUE(db.isTableExist(newTabName).first);

	auto table = db.getTable(newTabName);
	std::string value;
	ASSERT_TRUE(table->get(key, value).IsNotFound());
		
	ASSERT_TRUE(table->put(key, "world").ok());

	ASSERT_TRUE(table->del(key).ok());

	ASSERT_TRUE(db.dropTable(newTabName));

    db.close();
    ASSERT_FALSE(db.isOpened());
}

TEST_F(RocksdbTest, testGetPutDeleteInDefault){
    Rocksdb db(_dirname);

    db.openExist();
    ASSERT_TRUE(db.isOpened());

	//default table get/put/del
	{
		auto defTable = db.getTable(_defTabName);
		std::string value;
		ASSERT_TRUE(defTable->get(key, value).IsNotFound());
		
		ASSERT_TRUE(defTable->put(key, "world").ok());

		ASSERT_TRUE(defTable->del(key).ok());
	}
	//create newTable	
	{
		auto && p = db.isTableExist(newTabName);
		if(!p.first){
			ASSERT_TRUE(db.createTable(newTabName) != nullptr);
		}
		ASSERT_TRUE(db.isTableExist(newTabName).first);

		auto table = db.getTable(newTabName);
		std::string value;
		ASSERT_TRUE(table->get(key, value).IsNotFound());
		
		ASSERT_TRUE(table->put(key, "world").ok());

		ASSERT_TRUE(table->del(key).ok());


		ASSERT_TRUE(db.dropTable(newTabName));
	}

    db.close();
    ASSERT_FALSE(db.isOpened());
}
